package net.lulihu.pangolin.headless.common.container;

import lombok.extern.slf4j.Slf4j;
import net.lulihu.pangolin.headless.common.container.exception.BeanClassExistException;
import net.lulihu.pangolin.headless.common.container.exception.BeanNotExistException;
import net.lulihu.pangolin.headless.common.container.templet.BeanContainer;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 默认对象容器
 */
@Slf4j
public class DefaultBeanContainer implements BeanContainer {

    private final Map<Class<?>, Object> containerMap;
    private final Lock readLock;
    private final Lock writeLock;

    DefaultBeanContainer() {
        this.containerMap = new ConcurrentHashMap<>();
        ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        this.readLock = readWriteLock.readLock();
        this.writeLock = readWriteLock.writeLock();
    }

    @Override
    public void addBean(Object bean) throws BeanClassExistException {
        addBean(bean.getClass(), bean);
    }

    @Override
    public void addBean(Class<?> beanClass, Object bean) throws BeanClassExistException {
        try {
            writeLock.lock();//先加写锁

            if (containerMap.containsKey(beanClass))
                throw new BeanClassExistException("[" + beanClass + "]类型已经存在");

            containerMap.put(beanClass, bean);
        } finally {
            writeLock.unlock();//解锁
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T getBean(Class<?> beanClass) throws BeanNotExistException {
        try {
            readLock.lock();//先加读锁

            Object bean = containerMap.get(beanClass);

            if (bean == null) throw new BeanNotExistException("[" + beanClass + "] 不存在");

            return (T) bean;
        } finally {
            readLock.unlock();//解锁
        }
    }

    @Override
    public boolean contains(Class<?> beanClass) {
        try {
            readLock.lock();//先加读锁
            return containerMap.containsKey(beanClass);
        } finally {
            readLock.unlock();//解锁
        }
    }

}
